//TIPS: 实现导出修改的平滑过渡
export * from './is'
import dayjs from 'dayjs'
import { isEqual as isEqualRow, get as getRaw } from 'lodash-es'
import {
  isSetObject,
  isNumber,
  isObject,
  isArray,
  isEmptyObject,
  isEmptyArr,
  isNullOrEmpty,
  isFunction
} from '@/utils/is'
import { useUserStoreWithOut } from '@/store/modules/user'
import { $getPublishedApplicationId } from '@/utils/common'

export const isEqual = isEqualRow
export const get = getRaw;
export const $isEmptyArr = isEmptyArr
export const $isNullOrEmpty = isNullOrEmpty

export function cloneDeep(obj: any) {
  // 如果当前数据不是对象类型，则不需要深拷贝，直接返回即可
  if (typeof obj !== 'object' || obj === null) {
    return obj
  }

  return JSON.parse(JSON.stringify(obj))
}

/**
 * 获取应用ID
 */
export function getApplicationId() {
  return import.meta.env.VITE_BASE_APP_ID || $getPublishedApplicationId()
}

/**
 * 获取两个简单数组的差集
 * @param {Array} arr1
 * @param {Array} arr2
 */
export function getDifferenceArray(arr1, arr2) {
  if (isArray(arr1) && isArray(arr2)) {
    const set1 = new Set(arr1)
    const set2 = new Set(arr2)
    return Array.from(new Set([...set1].filter(x => !set2.has(x))))
  }
  return []
}

export function merge(source, other) {
  if (!isObject(source) || !isObject(other)) {
    return other === undefined ? source : other
  }
  // 合并两个对象的 key，另外要区分数组的初始值为 []
  return Object.keys({
    ...source,
    ...other
  }).reduce(
    (acc, key) => {
      // 递归合并 value
      source[key] = merge(source[key], other[key])
      acc[key] = source[key]
      return acc
    },
    Array.isArray(source) ? [] : {}
  )
}

/**
 * 空对象判断
 */
export function $isEmptyObject(obj) {
  for (const _name in obj) {
    return false
  }
  return true
}

/**
 * 处理页面跳转
 * @param {String} href 目标URL
 * @param $router
 * @param {String} target  跳转方式 _self（默认）当前页跳转， _blank为新页面打开
 * @param {String} routeType  跳转方式： auto（默认） -> 通过判断url中是否包括http判断是否使用a标签进行跳转；a ->强行a标签；router->强行router-link
 */
export function $handleRedirect(href: string, $router: any, target = '_self', routeType = 'auto') {
  const isAlink = (routeType === 'auto' && href.indexOf('http') > -1) || routeType === 'a' // 判断是否采用非router路由模式
  let targetUrl = { href } // 构建链接，形式同$router.resolve后的结果
  if (!isAlink) {
    targetUrl = $router.resolve(href) // 如果是router路由模式，通过resolve的方式构建链接用以兼容实现Vue router-link 模式下的新窗口链接（_blank）
  }
  window.open(targetUrl.href, target)
}

// 给数字添加千分位分隔符
export function addThousandsSeparatorToNumber(number) {
  const formatNumber = Number(number)

  // 如果当前值不能转成数字，则返回原值；否则对其添加千分位分隔符
  if (isNaN(formatNumber)) {
    return number
  } else {
    return formatNumber.toLocaleString()
  }
}

/**
 * 获取持久化信息
 * @param key 存储的key
 */
export function localGet(key: string) {
  try {
    const result = JSON.parse(localStorage.getItem(key) || '{}')
    if (result.hasOwnProperty('value')) {
      return result.value
    } else {
      return result
    }
  } catch (error) {
    return
  }
}

interface BlockReference<T> {
  node: T | null
}
interface HandleNode<T> {
  (node: T): T | null
}
interface HandleLeafNode<T> {
  (node: T, reference: BlockReference<T>): void
}

// 通过handleNode递归逐个处理树形节点、handleLeafNode对叶子节点进行处理。data为需要递归的树结构
export function traversalTreeStructure<T extends { children?: T[]; [key: string]: any }>(
  data: Array<T>,
  handleNode: HandleNode<T> = node => ({ ...node, children: [] }),
  handleLeafNode?: HandleLeafNode<T>,
  childrenKey = 'children'
): Array<T> {
  if (!isArray(data)) {
    return []
  }
  const filterData: T[] = []
  for (let index = 0; index < data.length; index++) {
    // 创建引用对象，用于过滤叶子节点的实现
    const reference: BlockReference<T> = { node: null }
    reference.node = handleNode(data[index])
    if (isArray<T>(data[index][childrenKey])) {
      // 如果有children继续递归
      const result = traversalTreeStructure(data[index][childrenKey], handleNode, handleLeafNode, childrenKey)
      if (result.length && reference.node) {
        reference.node.children = result
      }
    } else {
      handleLeafNode && handleLeafNode(data[index], reference)
    }
    reference.node && filterData.push(reference.node)
  }
  return filterData
}
/**
 *  条件类型枚举
 *string
 * @export
 * @enum {string}
 */
export enum ConditionType {
  // 空
  IS_NULL = 'IS_NULL',
  // 非空
  IS_NOT_NULL = 'IS_NOT_NULL',
  // 属于
  BELONG = 'BELONG',
  // 不属于
  NOT_BELONG = 'NOT_BELONG',
  // 包含
  CONTAIN = 'CONTAIN',
  // 不包含
  NOT_CONTAIN = 'NOT_CONTAIN',
  // 开头是
  PRE_IS = 'PRE_IS',
  // 开头不是
  PRE_NOT_IS = 'PRE_NOT_IS',
  // 结尾是
  END_IS = 'END_IS',
  // 结尾不是
  END_NOT_IS = 'END_NOT_IS',
  // 介于
  BETWEEN = 'BETWEEN',
  // 不介于
  NOT_BETWEEN = 'NOT_BETWEEN',
  // 等于
  EQUALS = 'EQUALS',
  // 不等于
  NOT_EQUALS = 'NOT_EQUALS',
  // 某个日期之前
  DATE_LT = 'DATE_LT',
  // 某个日期之后
  DATE_GT = 'DATE_GT',
  // 全等
  EQ = 'EQ',
  // 不全等
  NE = 'NE',
  // 大于
  GT = 'GT',
  // 小于
  LT = 'LT',
  // 大于等于
  GE = 'GE',
  // 小于等于
  LE = 'LE',
  // 空数组
  IS_NULL_ARRAY = 'IS_NULL_ARRAY',
  // 非空数组
  IS_NOT_NULL_ARRAY = 'IS_NOT_NULL_ARRAY'
}
/**
 * 左值为null/undefined时，可以使用的条件类型
 */
const leftValueCanBeNull = [
  ConditionType.IS_NULL,
  ConditionType.IS_NOT_NULL,
  ConditionType.IS_NOT_NULL_ARRAY,
  ConditionType.IS_NULL_ARRAY,
  ConditionType.EQUALS,
  ConditionType.NOT_EQUALS,
  ConditionType.EQ,
  ConditionType.NE
]

/**
 * 检查条件是否成立
 * @param leftValue
 * @param conditionType
 * @param rightValue
 * @returns
 */
export const checkCaseCondition = (leftValue: any, conditionType: ConditionType, rightValue: any) => {
  if (!conditionType) {
    return false
  }
  // 如果当前值值不存在，且左值不能为null/undefined时 则不满足条件
  if (leftValue === undefined || leftValue === null) {
    if (!leftValueCanBeNull.includes(conditionType)) {
      return false
    }
  }

  switch (conditionType) {
    case ConditionType.CONTAIN: // 包含
      return leftValue.indexOf(rightValue) > -1
    case ConditionType.NOT_CONTAIN: // 不包含
      return leftValue.indexOf(rightValue) === -1
    case ConditionType.IS_NULL: // 为空
      return !leftValue
    case ConditionType.IS_NOT_NULL: // 非空
      return !!leftValue
    case ConditionType.PRE_IS: // 开头是
      return leftValue.startsWith(rightValue)
    case ConditionType.PRE_NOT_IS: // 开头不是
      return !leftValue.startsWith(rightValue)
    case ConditionType.END_IS: // 结尾是
      return leftValue.endsWith(rightValue)
    case ConditionType.END_NOT_IS: // 结尾不是
      return !leftValue.endsWith(rightValue)
    case ConditionType.EQUALS: // 等于
      return leftValue == rightValue
    case ConditionType.NOT_EQUALS: // 不等于
      return leftValue != rightValue
    case ConditionType.GT: // 大于
      return leftValue > rightValue
    case ConditionType.LT: // 小于
      return leftValue < rightValue
    case ConditionType.EQ: // 全等
      return leftValue === rightValue
    case ConditionType.NE: // 不全等
      return leftValue !== rightValue
    case ConditionType.GE: // 大于等于
      return leftValue >= rightValue
    case ConditionType.LE: // 小于等于
      return leftValue <= rightValue
    case ConditionType.IS_NULL_ARRAY: //空数组
      return !leftValue.length
    case ConditionType.IS_NOT_NULL_ARRAY: // 非空数组
      return !!leftValue.length
    default:
      return false
  }
}
/**
 * 判断单元格是否可编辑
 * @param {*} columnsConfig
 * @param {*} rowData
 * @param {*} conditionValueMap
 * @returns
 */
export const judgeCellEditable = (columnsConfig, rowData, conditionValueMap) => {
  if (columnsConfig.rowEditConditions) {
    for (let index = 0; index < columnsConfig.rowEditConditions.length; index++) {
      const { condition, editable } = columnsConfig.rowEditConditions[index]
      const { conditionId, conditionKey, conditionType } = condition
      // 如果条件满足，则使用该条件的值
      if (
        checkCaseCondition(
          rowData[conditionKey],
          conditionType,
          conditionValueMap[`${conditionId}__$__${conditionKey}`]
        )
      ) {
        // 返回该条件的可编辑状态
        return editable
      }
    }
  }
  if (columnsConfig.rowEdit) {
    if (
      isNumber(rowData['__SUB_INDEX']) &&
      rowData['__SUB_INDEX'] > 0 &&
      /^[a-zA-Z]_[\w]*$/.test(columnsConfig.dataIndex)
    ) {
      return false;
    }
  }
  return columnsConfig.rowEdit
}

/**
 * 获取单元格内容样式
 * @param {*} contentConfig
 * @param {*} rowData
 * @param {*} conditionValueMap
 * @returns
 */
export function generateContentStyle(contentConfig, rowData, conditionValueMap) {
  if (contentConfig.conditionStyle) {
    for (let index = 0; index < contentConfig.conditionStyle.length; index++) {
      const { condition, style } = contentConfig.conditionStyle[index]
      // 如果没有条件配置或样式配置，则跳过该条件样式
      if (!condition || !style) {
        continue
      }
      const { conditionId, conditionKey, conditionType } = condition
      // 如果条件满足，则使用该条件的样式覆盖默认样式
      if (
        checkCaseCondition(
          rowData[conditionKey],
          conditionType,
          conditionValueMap[`${conditionId}__$__${conditionKey}`]
        )
      ) {
        return style
      }
    }
  }
  return contentConfig.defaultStyle ?? {}
}
/**
 * 在模板中渲染字符串的通用处理函数
 *
 * @param val 待渲染的值
 * @param connector 如果为数组时的连接符
 * @returns
 */
export const renderStringInTemplate = (val: any, connector = '-'): any => {
  if (isArray(val)) {
    return val.map((item: any) => renderStringInTemplate(item, connector)).join(connector)
  }
  // 只支持三种基本数据类型
  if (typeof val === 'string' || typeof val === 'number' || typeof val === 'boolean') {
    return val
  }
  return ''
}

/**
 * 生成应用的basePath
 * @param {String | Number} applicationId
 * @return {String} 根据规则生成的basePath
 */
export function fetchBasePath(applicationId: number, type = 'lowCode') {
  const typeMap: any = {
    adv: 'adv',
    lowCode: 'app',
    pc: 'app',
    h5: 'h5'
  }
  const prefix = typeMap[type.toLocaleLowerCase()] ? typeMap[type.toLocaleLowerCase()] : 'app'
  return `${prefix}_${applicationId}`
}

// 面包屑点击跳转
export function handleBreadcrumbJump(router, info) {
  const { targetPage, query, applicationId } = info
  let targetUrl =
    targetPage.settingType === 'CUSTOM_PAGE' ? `/${fetchBasePath(applicationId)}/customPage` : targetPage.url
  if (targetUrl.startsWith('app_')) {
    targetUrl = '/' + targetUrl
  }
  if (targetPage.settingType === 'CUSTOM_PAGE') {
    // 自定义页面将URL推入到query中
    query['iframe_url'] = targetPage.modelId
  }
  if (targetPage.settingType === 'BI_DASH_BOARD' && isNumber(targetPage.modelId)) {
    // BI预览页面id传递方式采用query，直接在路由中未生效，此处推入到query中
    query['id'] = targetPage.modelId
  }
  const jumpInfo = {
    path: getFullUrl(targetUrl), // 跳转地址
    query
  }
  const routeUrl = router.resolve(jumpInfo)
  let url = routeUrl.href
  // 判断是否是MicroApp的子应用
  const microAppData = window.microApp?.getData() ?? window.eventCenterForViteApp?.getData()
  if (microAppData) {
    const urlList: string[] = []
    Object.keys(jumpInfo.query).forEach(item => {
      const urlItem = item + '=' + jumpInfo.query[item]
      urlList.push(urlItem)
    })
    // 判断要跳转的地址是否是用户自定义输入的
    const customJumpPath = targetPage.settingType === 'CUSTOM_PAGE' ? jumpInfo.query.iframe_url : jumpInfo.path
    // 自定义跳转页面不是其他平台的菜单，则直接使用全路径
    if (targetPage.settingType === 'CUSTOM_PAGE' && customJumpPath.indexOf('/allin-app/') === -1) {
      url = jumpInfo.query.iframe_url + '?' + urlList.join('&')
    } else if (customJumpPath.indexOf('/allin-app/') !== -1) {
      // 目标页面是其他平台的菜单
      let jumpPath = customJumpPath.substring(customJumpPath.indexOf('/allin-app/'))
      // 配置有参数，需要加参数添加到路由后面
      if (urlList.length) {
        // 跳转的路径本身带有参数
        if (jumpPath.indexOf('?') !== -1) {
          jumpPath += '&' + urlList.join('&')
        } else {
          jumpPath += '?' + urlList.join('&')
        }
      }
      url = location.origin + jumpPath
    } else {
      // 目标页面就是低代码项目本身的页面
      // 这里兼容二级域名
      const basePath = microAppData.baseroute || '/allin-app'
      url = location.origin + basePath + url
    }
  }
  // 跳转
  if (microAppData) {
    window.location.href = url
  } else {
    router.push(jumpInfo)
  }
}

// 防抖
export function debounce(fn, wait) {
  let timer = null
  return function () {
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      timer = null
      fn.apply(this, arguments)
    }, wait)
  }
}

// 节流
export function throttle(fn, delay) {
  let lastTime = 0
  return function () {
    const nowDate = Date.now()
    if (nowDate - lastTime > delay) {
      // 如果当前触发时间减去最后一次触发时间大于需要延迟的事件，就执行事件
      lastTime = nowDate
      fn && fn.apply(this, arguments)
    }
  }
}

/**
 * 判断是否有权限
 */
export function permission(permissionVal: string | number) {
  const userStore = useUserStoreWithOut()
  const permissionCodeMap: string[] = userStore.getPermissionMap || []
  return permissionCodeMap.some((item) => item.includes(String(permissionVal)));
}

export function switchCase(params: any[]) {
  const [condition, ...rest] = params
  const conditionIndex = rest.indexOf(condition)
  if (conditionIndex === -1) {
    return null
  }
  return rest[conditionIndex + 1]
}

// -------------------- 大屏 ---------------------------

/**
 * 数组/对象遍历
 * @param object 要遍历的对象
 * @param formatCallback 要执行的方法
 */
export function $each(object, formatCallback) {
  let index = 0
  if (isArray(object)) {
    // Object 没有length, 只有 Array 有
    const { length } = object
    for (; index < length; index++) {
      formatCallback(object[index], index)
    }
  } else if (isSetObject(object)) {
    for (index of object) {
      formatCallback(index)
    }
  } else if (isObject(object)) {
    for (index in object) {
      formatCallback(object[index], index)
    }
  }
}

/**
 * 收集被联动的组件信息
 * @param {*} relationSetMap 当前组件关联的联动组件信息
 * @return
 * {
 *  联动组件ID： [
 *    联动的维度A,
 *    联动的维度B
 *  ]
 * }
 */
export const collectComponentLinkage = (relationSetMap, dimensionMap = {}, reset, externalData) => {
  const componentRelationSet = {}
  $each(relationSetMap, (componentRelationList, relationKey) => {
    $each(componentRelationList, componentRelation => {
      // 联动关联的维度 及 组件ID
      const { relationFieldList, id } = componentRelation

      // 遍历联动的所有维度
      relationFieldList.forEach(field => {
        if (dimensionMap[relationKey]) {
          // active 值主要针对表格，因为表格如果设置两个联动的话，需要点击哪个联动哪一个
          const { value, dateFormat, active } = dimensionMap[relationKey]
          // 如果存在externalData，说明接的是外部数据，需要直接赋值
          if (externalData && Object.keys(externalData).length) {
            field.filterValue = externalData[Object.keys(externalData)[0]]
          } else {
            // 给字段赋值需要过滤的值
            field.filterValue = value
          }
          // 日期类型的需要记录转换的格式
          field.filterDateFormat = dateFormat
          // 点击的是否是需要联动的
          field.isLinkageActive = active
        }
        // 如果点击的维度不存在，则直接return
        if (!reset && isEmptyObject(dimensionMap[relationKey])) {
          return {}
        }
        if (field.isLinkageActive) {
          // 判断是否已经存在组件id
          if (componentRelationSet[id]) {
            componentRelationSet[id].push(JSON.parse(JSON.stringify(field)))
          } else {
            componentRelationSet[id] = [JSON.parse(JSON.stringify(field))]
          }
        }
      })
    })
  })

  return componentRelationSet
}

// 根据交互事件中选择的位置信息获取x,y值
export function getPosition(position, width, height) {
  const positionInfo = {}
  // 获取屏幕缩放
  const getElement = document.getElementById('visualizationPageRoot')
  let scale = 1
  if (getElement.style.transform) {
    scale = getElement.style.transform.split('(')[1].split(')')[0]
  }
  // 获取可视屏幕的高度和宽度
  const clientHeight =
    document.documentElement.clientHeight == 0 ? getElement.clientHeight : document.documentElement.clientHeight
  const clientWidth =
    document.documentElement.clientWidth == 0 ? getElement.clientWidth : document.documentElement.clientWidth
  const topCenter = (clientWidth / 2 - (width * scale) / 2) / scale
  const bottomCenter = (clientHeight - height * scale) / scale
  const leftCenter = (clientHeight / 2 - (height * scale) / 2) / scale
  const rightCenter = (clientWidth - width * scale) / scale
  switch (position) {
    case 'top-center':
      positionInfo.x = topCenter
      positionInfo.y = 0
      break
    case 'bottom-center':
      positionInfo.x = topCenter
      positionInfo.y = bottomCenter
      break
    case 'center-center':
      positionInfo.x = topCenter
      positionInfo.y = leftCenter
      break
    case 'left-center':
      positionInfo.x = 0
      positionInfo.y = leftCenter
      break
    case 'right-center':
      positionInfo.x = rightCenter
      positionInfo.y = leftCenter
      break
    default:
      break
  }
  return positionInfo
}
/**
 * 收集被跳转的组件信息
 * @param {*} relationSetMap 当前组件关联的联动组件信息
 * @return
 * [
 *  { url: '跳转地址A', target: '_self' },
 *  { url: '跳转地址B', target: '_blank' }
 * ]
 */
export function collectComponentJump(componentJumpMap, dimensionMap = {}, pageType) {
  const urlList = []

  // 处理内部跳转、外部跳转
  const methods = {
    inner: handleInner,
    outer: handleOuter
  }
  // 过滤配置的跳转信息
  $each(componentJumpMap, (jumpList, type) => {
    jumpList.forEach(config => {
      const urlItem = methods[type] && methods[type](config, dimensionMap, pageType)
      urlList.push(urlItem)
    })
  })
  return urlList
}

// 处理内部跳转数据
function handleInner(config, dimensionMap, pageType) {
  const { dashboardId, openType, params, field } = config

  // 表格跳转只跳转当前选择的，而echarts则全部触发，使用active进行标记点击的图表
  if (dimensionMap[field] && !dimensionMap[field].active) {
    return {}
  }

  // 跳转过滤条件
  const filter = {}
  // 跳转全局参数字符串
  let globalParameterStr = ''
  // 拼装跳转请求参数
  $each(params, item => {
    const { datasetId, source: sourceFields, target: targetFields } = item
    const sourceField = sourceFields?.field
    const { field: targetField, parameterType: targetParameterType } = targetFields || {}
    // 获取映射的值
    const { value, dateFormat } = dimensionMap[sourceField]
    if (targetParameterType === 'dataset') {
      // 拼装过滤参数
      const requestParam = { filterValue: encodeURIComponent(value), filterDateFormat: dateFormat }

      if (filter[datasetId]) {
        filter[datasetId][targetField] = requestParam
      } else {
        filter[datasetId] = { [targetField]: requestParam }
      }
    }
    if (targetParameterType === 'custom') {
      globalParameterStr += `&${targetField}=${encodeURIComponent(value)}`
    }
  })
  const parameterStr = isEmptyObject(filter)
    ? globalParameterStr.substr(1)
    : `filter=${JSON.stringify(filter)}${globalParameterStr}`
  const url = pageType ? `${dashboardId}?type=${pageType}&${parameterStr}` : `${dashboardId}?${parameterStr}`
  return {
    url: url,
    // 跳转方式，默认新窗口
    target: openType || '_blank'
  }
}

// 处理外部跳转数据
function handleOuter(config, dimensionMap) {
  const { url, openType, fieldMap, field } = config

  // 表格跳转只跳转当前选择的，而echarts则全部触发，使用active进行标记点击的图表
  if (dimensionMap[field] && !dimensionMap[field].active) {
    return {}
  }

  // 获取映射的值
  const mapping = {}

  /**
   * 动态生成正则表达式，进行替换相应的值
   * resource： location.origin/[国家]/[地区]/[销售人员]
   * target  :  location.origin/中国/北京/张三
   */
  let dynamicRegex = ''
  const regexPrefix = '\\['
  const regexSuffix = '\\]'

  // 动态生成正则
  $each(fieldMap, (fieldName, key) => {
    const { value } = dimensionMap[key]
    mapping[`[${fieldName}]`] = encodeURIComponent(value)
    dynamicRegex += `${regexPrefix}${fieldName}${regexSuffix}|`
  })

  return {
    url: dynamicRegex
      ? url.replace(
          new RegExp(dynamicRegex.substring(0, dynamicRegex.length - 1), 'g'),
          replacement => mapping[replacement]
        )
      : url,
    // 跳转方式，默认新窗口
    target: openType || '_blank'
  }
}

/**
 * 列表事件循环获取向前或者向后 id 标识
 * @param {*} newValue 需要特殊处理的值
 * @param {*} blockProp 组件属性，编译阶段使用
 */
export function $getCirculationKey(newValue, blockPropPanelInfo) {
  const panelList = blockPropPanelInfo.list
  let oldValue = blockPropPanelInfo.activeKey
  if (isEmptyArr(panelList)) {
    return
  }
  if (newValue !== 'back' && newValue !== 'forward') {
    return newValue
  }
  if (isNullOrEmpty(oldValue)) {
    oldValue = panelList[0].id
  }
  let currentIndex = 0
  panelList.forEach((item, index) => {
    if (oldValue === item.id) {
      currentIndex = index
    }
  })
  let resultIndex = 0
  if (newValue === 'forward') {
    if (currentIndex >= panelList.length - 1) {
      resultIndex = 0
    } else {
      resultIndex = currentIndex + 1
    }
  } else if (newValue === 'back') {
    if (currentIndex <= 0) {
      resultIndex = panelList.length - 1
    } else {
      resultIndex = currentIndex - 1
    }
  }
  blockPropPanelInfo.activeKey = panelList[resultIndex].id
  return panelList[resultIndex].id
}

/**
 *  获取随机ID，组件拖到预览视图后就会被设置个ID
 */
export function $guid(prefix) {
  function s4() {
    const baseNumber = 0x10000
    const radix = 16
    return Math.floor((1 + Math.random()) * baseNumber)
      .toString(radix)
      .substring(1)
  }

  return `${prefix ? `${prefix}-` : ''}${s4()}${s4()}-${s4()}`
}
/*  将数字进行千分位格式化 */
export function $formatPercentage(num) {
  //  分离整数部分及小数部分
  let [intPart, pointPart] = `${num}`.split('.')

  const reg = /\d{1,3}(?=(\d{3})+$)/g
  intPart = intPart.replace(reg, '$&,') // 完成整数部分千分位符号插入
  pointPart = !isNullOrEmpty(pointPart) ? `.${pointPart}` : '' // 如果分离出的小数部分存在，则补齐小数点
  return `${intPart}${pointPart}`
}

/**
 * 处理IOS不支持直接document.title修改标题方法
 * @param title
 */
export const setPageTitle = title => {
  const _body = document.getElementsByTagName('body')[0]
  document.title = title
  const _iframe = document.createElement('iframe')
  _iframe.style.display = 'none'
  _body.appendChild(_iframe)
  setTimeout(() => {
    document.body.removeChild(_iframe)
  }, 300)
}

const cloneIs = {
  Array: Array.isArray,
  Date: val => val instanceof Date,
  Set: val => Object.prototype.toString.call(val) === '[object Set]',
  Map: val => Object.prototype.toString.call(val) === '[object Map]',
  Object: val => Object.prototype.toString.call(val) === '[object Object]',
  Symbol: val => Object.prototype.toString.call(val) === '[object Symbol]',
  Function: val => Object.prototype.toString.call(val) === '[object Function]'
}

export function deepClone(value, weakMap = new WeakMap()) {
  // 2.2 函数深拷贝
  if (cloneIs.Function(value)) {
    if (/^function/.test(value.toString()) || /^\(\)/.test(value.toString()))
      return new Function('return ' + value.toString())()

    return new Function('return function ' + value.toString())()
  }

  // 3.Date 深拷贝
  if (cloneIs.Date(value)) return new Date(value.valueOf())

  // 4.判断如果是Symbol的value, 那么创建一个新的Symbol
  if (cloneIs.Symbol(value)) return Symbol(value.description)

  // 5.判断是否是Set类型 进行深拷贝
  if (cloneIs.Set(value)) {
    // 5.1 浅拷贝 直接进行解构即可
    // return new Set([...value])

    // 5.2 深拷贝
    const newSet = new Set()
    for (const item of value) newSet.add(deepClone(item), weakMap)
    return newSet
  }

  // 6.判断是否是Map类型
  if (cloneIs.Map(value)) {
    // 6.1 浅拷贝 直接进行解构即可
    // return new Map([...value])

    // 6.2 深拷贝
    const newMap = new Map()
    for (const item of value) newMap.set(deepClone(item[0], weakMap), deepClone(item[1], weakMap))
    return newMap
  }

  // 9.判断weakMap是否有值 有值的情况下就直接将值返回就可以
  if (weakMap.has(value)) return weakMap.get(value)

  // 11.2 判断数组
  if (cloneIs.Array(value)) {
    const newArr = []
    for (const item in value) newArr[item] = deepClone(value[item], weakMap)
    return newArr
  }

  // 1.如果不是对象类型则直接将当前值返回
  if (!cloneIs.Object(value)) return value

  // 7.判断传入的对象是数组, 还是对象
  const newObj = cloneIs.Array(value) ? [] : {}

  // 10.当weakMap没有值时，将originValue作为key, newObj作为value
  weakMap.set(value, newObj)

  for (const key in value) {
    // 11.1 判断数组
    if (cloneIs.Array(value[key])) deepClone(value[key], weakMap)

    weakMap.set(value, newObj)
    // 8 进行递归调用
    newObj[key] = deepClone(value[key], weakMap)
  }

  // 4.1 对Symbol作为key进行特殊的处理 拿到对象上面的所有Symbol key，以数组形式返回
  const symbolKeys = Object.getOwnPropertySymbols(value)
  for (const sKey of symbolKeys) {
    // 4.2 这里没有必要创建一个新的Symbol
    // const newSKey = Symbol(sKey.description)

    // 4.3 直接将原来的Symbol key 拷贝到新对象上就可以了
    newObj[sKey] = deepClone(value[sKey], weakMap)
  }

  return newObj
}

/**
 * 代码中使用动态获取静态图片地址
 * @param name: asstes/images目录下的图片名称
 */
export function getAssetsFile(name: string) {
  return new URL(`../assets/images/${name}`, import.meta.url).href
}
/**
 * 日期转换
 * @param {*} serial_number
 * @param {*} format
 * @returns
 * %c 月份 1-12
 * %d 月份中的第几天 01-31
 * %e 月份中的第几天 1-31
 * %f 秒的分数6位
 * %H 小时 00-23
 * %h 小时 01-12
 * %i 分钟 00-59
 * %j 一年中的某一天 001-366
 * %k 小时 00-23
 * %l 小时 01-12
 * %m 月份 01-12
 * %S 秒 00-59
 * %s 秒 00-59
 * %T 时间 24小时制
 * %Y 年份 4位
 * %y 年份 2位
 */
export function dateParse(serial_number, format) {
  const formatParse = format.replace(/(%[c|d|e|f|H|h|i|j|k|l|m|S|s|T|Y|y])/g, match => {
    switch (match) {
      case '%c':
        return 'M'
      case '%d':
        return 'DD'
      case '%e':
        return 'D'
      case '%f':
        return 'SSS'
      case '%H':
      case '%k':
      case '%T':
        return 'HH'
      case '%h':
      case '%l':
        return 'hh'
      case '%i':
        return 'mm'
      case '%m':
        return 'MM'
      case '%S':
      case '%s':
        return 'ss'
      case '%Y':
        return 'YYYY'
      case '%y':
        return 'YY'
      default:
        return match
    }
  })
  return dayjs(serial_number, formatParse).format('YYYY-MM-DD HH:mm:ss')
}

/**
 * 用于移动端单元格合并，获取当前单元格grid占比样式
 * @param {RowData} row
 * @param {ColData} col
 * @param {number} index
 * @returns
 */
export function getGridStyle(row, col, index) {
  let end = index + 1
  if (row.__ADDITION_ROW_INFO.rowList.includes(col.dataIndex)) {
    end = index + 1 + row.__ADDITION_ROW_INFO.rowSpan
  }
  return index + 1 + ' / ' + end
}
/**
 * 用于移动端单元格合并，判断是否渲染当前单元格
 * @param {RowData} row
 * @param {ColData} col
 * @returns
 */
export function getCellRenderAble(row, col) {
  if (row.__ADDITION_ROW_INFO.extra && row.__ADDITION_ROW_INFO.rowList.includes(col.dataIndex)) {
    return false
  }
  return true
}

const dateDif = (endTime, startTime, unit = 'd') => {
  const typeMap = {
    y: 'year',
    M: 'month',
    d: 'day',
    h: 'hour',
    m: 'minute',
    s: 'second'
  }
  return dayjs(endTime).diff(dayjs(startTime), typeMap[unit], true)
}
// 公式计算处理策略函数
export const formulaStrategy = {
  IF: (condition, first, second) => (condition ? first : second),
  DATE: serial_number => dayjs(serial_number).format('YYYY-MM-DD'),
  DAY: serial_number => dayjs(serial_number).date(),
  DAYS: (endTime, startTime) => dayjs(endTime).diff(startTime, 'day'),
  SWITCH: (...args) => switchCase([...args]),
  HOUR: serial_number => dayjs(serial_number).hour(),
  MINUTE: serial_number => dayjs(serial_number).minute(),
  MONTH: serial_number => dayjs(serial_number).month() + 1,
  NOW: () => dayjs().format('YYYY-MM-DD HH:mm:ss'),
  SECOND: serial_number => dayjs(serial_number).second(),
  DATE_PARSE: (serial_number, format = '%Y-%m-%d %T:%i:%s') => dateParse(serial_number, format),
  DATEDIF: (...args) => dateDif(...args),
  CURRENT_DATE: () => dayjs().format('YYYY-MM-DD'),
  WEEK: serial_number => dayjs(serial_number).week(),
  // 星期天为一周的第一天 返回0 则转为 7
  DAY_OF_WEEK: serial_number => dayjs(serial_number).day() || 7,
  YEAR: serial_number => dayjs(serial_number).year(),
  ABS: number => Math.abs(number),
  TRUNCATE: number => (number?.toString().includes('-') ? Math.ceil(number) : Math.floor(number)),
  GREATEST: (...args) => Math.max(...args),
  LEAST: (...args) => Math.min(...args),
  CONCAT: (...args) => args.join(''),
  LOWER: (text = '') => text.toLowerCase(),
  UPPER: (text = '') => text.toUpperCase(),
  LEFT: (text = '', num_chars = 1) => text.slice(0, num_chars),
  RIGHT: (text = '', num_chars = 1) => text.slice(-num_chars)
}

// 获取基础路径
export const getAppBaseUrl = () => {
  const microAppData = window.eventCenterForViteApp?.getData()
  // 当有microApp信息时，有breadcrumbList则认为是productContainer，不处理二级域名
  if(microAppData && !microAppData.hasOwnProperty("type") && microAppData.hasOwnProperty("breadcrumbList")){
    return ""
  }
  const userStore = useUserStoreWithOut()
  const { productCode, tenantCode } = userStore
  const { pathname } = window.location
  const reg = new RegExp(/^\/prd[\w]+\/tnt[\w]+/)
  if (productCode && tenantCode) {
    return `/${productCode}/${tenantCode}`
  } else if (reg.test(pathname)) {
    // resolve sometime have no userStore question.
    return pathname.match(reg)[0]
  }
  return ''
}

// 获取全路径
export const getFullUrl = path => {
  let _path = path
  if(!_path){
    return _path
  }
  if (!_path.startsWith('/')) {
    _path = `/${_path}`
  }
  const basePath = getAppBaseUrl()
  const reg = new RegExp(/^\/prd[\w]+\/tnt[\w]+/)
  if (reg.test(basePath) && !reg.test(_path)) {
    _path = basePath + _path
  }
  return _path
}

// 获取组件参数值
export const getComponentParamsValue = (value: any) => {
  if (isFunction(value)) {
    return value()
  }
  return value
}
